"""General RDF data store functions"""
from django.db.transaction import commit_on_success
from django.db.models import fields, get_app
from django.core.exceptions import ImproperlyConfigured
import RDF 

w3type = RDF.Uri("http://www.w3.org/1999/02/22-rdf-syntax-ns#type")


def memory_model(data,url=None):
    """Create an in-memory Redland model, fill it with <data>
    if supplied (for blank model, call memory_model(None)
    >>> model = memory_model(None)
    """
    storage = RDF.Storage(storage_name="memory", name="memory",
                  options_string="")
    # model needs URL, it is not re-used.
    if url is None: url = 'http://catalog.terradue.com/'
    model = RDF.Model(storage)
    parser = RDF.Parser()
    if data: parser.parse_string_into_model(model, data, url)
    return model

def get_model(app_label, module_name):
    """
    Need a special model that supports abstract classes,
    such as is used with envisat. The standard Django
    get_model insists that the models are concrete.
    """
    try:
        app = get_app(app_label)
    except ImproperlyConfigured:
        raise Http404("no such app")

    props = app.__dict__.keys()
    for i in range(len(props)):
        if props[i].lower() == module_name:
            return app.__dict__[props[i]]
    raise Http404("no such model")

def load_to_django(model,django_model):
    s = RDF.Statement(None, w3type, dclite4g.DataSet.uri)
    for r in model.find_statements(s):
        #print r
        # @@ workaround - inherit schema-mandatory properties from
        # Series, explicitly here.
        model = _augment_model(model,r.subject)
        try:
            print "creating", r.subject
            django_model.objects.rdf_get_or_create(model, r.subject)
            # if suucessful, store the rdf annotations too.
            make_rdf_annotations(django_model,model)
        except Exception, e:
            print e
            raise

@commit_on_success
def make_rdf_annotations(django_model,rdf_model):
    dest_model = django_model._meta.rdf.model
    for s in _annotation_filter(rdf_model):
        dest_model.add_statement(s)

# should be refactored to allow passing in a function or 
# using this one as a default filter.
def _annotation_filter(model):
    ## we only support annotation with certain types
    queries = [

    ## All statements about a linked contact person/agent
"""
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX dc: <http://purl.org/dc/elements/1.1/>
PREFIX foaf: <http://xmlns.com/foaf/spec/'>
SELECT DISTINCT ?s, ?p, ?o {
    ?s rdf:type foaf:Person .
    ?s ?p ?o
}
""",
"""
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX dc: <http://purl.org/dc/elements/1.1/>
PREFIX foaf: <http://xmlns.com/foaf/spec/'>
SELECT DISTINCT ?s, ?p, ?o {
    ?s rdf:type foaf:Agent .
    ?s ?p ?o
}
""",
"""
PREFIX dc: <http://purl.org/dc/elements/1.1/>
SELECT DISTINCT ?s, ?p, ?o {
    ?s dc:contact ?o .
    ?s ?p ?o
}
""",
   ## All statements about a keyword or other bit of taxonomy
"""
PREFIX dc: <http://purl.org/dc/elements/1.1/>
SELECT DISTINCT ?s, ?p, ?o {
    ?s dc:subject ?o .
    ?s ?p ?o
}
""",
]
    for q in queries:
        #print q
        for r in RDF.SPARQLQuery(q).execute(model):
            yield RDF.Statement(r["s"], r["p"], r["o"])


if __name__ == '__main__':
    import doctest
    doctest.testmod()

    


